using System.Collections.Generic;
using System.IO;

namespace Framework.DataTable
{
    public abstract class DataTableLoader<T> : IDataTableLoader where T : class, IDataTable, new()
    {
        public const string BRANCH_TAG = "@";
        protected List<T> DataList { get; private set; }
        private Queue<T> _itemPool = new Queue<T>();
        public int ItemCount { get; protected set; }
        public string FileName
        {
            get
            {
                if (string.IsNullOrEmpty(Branch))
                {
                    return GetTableName();
                }
                return GetTableName() + BRANCH_TAG + Branch;
            }
        }
        public abstract string GetTableName();

        private int _decodeCount = -1;
        private int _decodeCountPreFrame = 0;
        protected ByteArray _buffer;
        protected int _decodeStartPos;
        private int _decodeIndex;
        private int _decodeEndPos;
        protected bool _loadSuccess;
        protected List<string> _branchs;
        private string _branch = "";
        private string _currentBranch = "";
        protected abstract T CreateItem();
        public string Branch
        {
            get
            {
                if (string.IsNullOrEmpty(_branch))
                {
                    if (_branchs != null && _branchs.Count > 0)
                    {
                        if (!string.IsNullOrEmpty(_branchs[0]))
                        {
                            _branch = _branchs[0];
                        }
                    }
                }
                return _branch;
            }
            set
            {
                if (ExistBranch(value))
                {
                    _branch = value;
                    _loadSuccess = _currentBranch == _branch;
                }
            }
        }
        public bool ExistBranch(string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                return true;
            }
            if (_branchs == null)
            {
                return false;
            }
            return _branchs.Contains(value);
        }
        public virtual bool LoadSuccess()
        {
            return _loadSuccess;
        }
        public T GetItem(int index)
        {
            if (index >= DataList.Count || index < 0) return null;
            var item = DataList[index];
            if (item == null && LazyDecode() && _buffer != null)
            {
                var offset = GetItemPosition(index);
                _buffer.SetPosition(offset);
                item = (T)DecodeItem(_buffer, GetItemFromPool());
                DataList[index] = item;
            }
            return item;
        }


#if UNITY_EDITOR
        public void EditorClear()
        {
            if (DataList == null)
            {
                DataList = new List<T>();
            }
            DataList.Clear();
            ItemCount = 0;
        }
        public virtual object ParseItem(string[] values)
        {
            if (DataList == null)
            {
                DataList = new List<T>();
            }
            T data = (T)CreateItem();
            data.Parse(values);
            DataList.Add(data);
            ItemCount = DataList.Count;
            return data;
        }

        public virtual void Encode(ByteArray buffer)
        {
            //count,end,pos0,pos1,...,data,data,...
            var count = DataList.Count;
            buffer.Write(count);//count
            buffer.Write(0);//endpos
            var pos = buffer.Position;
            buffer.SetPosition(pos + count * 4);//预留pos
            var itemPos = new List<int>();
            for (int i = 0; i < count; i++)
            {
                itemPos.Add(buffer.Position);
                DataList[i].Encode(buffer);
            }
            var end = buffer.Position;
            buffer.SetPosition(pos - 4);
            buffer.Write(end);
            var len = itemPos.Count;
            for (int i = 0; i < len; i++)
            {
                buffer.WriteInt(itemPos[i]);
            }
            buffer.SetPosition(end);
        }
#endif
        public void ReadHeader(ByteArray buffer)
        {
            _loadSuccess = true;
            _currentBranch = _branch;
            _buffer = buffer;
            ItemCount = buffer.ReadInt();
            _decodeEndPos = buffer.ReadInt();
            _decodeStartPos = buffer.Position;
            _decodeIndex = 0;
            if (DataList == null)
            {
                DataList = new List<T>(ItemCount);
            }
            for (int i = 0; i < ItemCount; i++)
            {
                if (i < DataList.Count)
                {
                    var item = DataList[i];
                    if (item == null)
                    {
                        continue;
                    }
                    _itemPool.Enqueue(item);
                    DataList[i] = null;
                    continue;
                }
                DataList.Add(null);
            }
            OnReadHeader();
            if (LazyDecode())
            {
                _decodeCount = 0;
                for (int i = 0; i < ItemCount; i++)
                {
                    _buffer.SetPosition(GetItemPosition(i));
                    AddIndex(_buffer, i);
                }
            }
            else
            {
                _decodeCount = ItemCount;
            }
        }
        protected virtual void OnReadHeader()
        {

        }
        public virtual bool LazyDecode()
        {
            return false;
        }
        protected virtual void BuildIndex()
        {

        }
        protected virtual void AddIndex(ByteArray buffer, int index)
        {
            //根据数据结构读出相应的key
        }
        protected int GetItemPosition(int index)
        {
            if (_buffer == null) return -1;
            var pos = _decodeStartPos + index * 4;
            _buffer.SetPosition(pos);
            return _buffer.ReadInt();
        }
        public int TryDecode()
        {
            if (_buffer == null)
            {
                FrameworkLog.LogError("ReadDecodeHeader first");
                return 0;
            }
            if (_decodeCount < 1)
            {
                return _decodeCount;
            }
            var max = _decodeCountPreFrame;
            if (max < 1)
            {
                max = _decodeCount < 1 ? 1 : _decodeCount;
            }
            while (_decodeCount > 0)
            {
                if (max-- < 1)
                {
                    break;
                }
                _decodeCount--;
                var offset = GetItemPosition(_decodeIndex);
                _buffer.SetPosition(offset);
                DataList[_decodeIndex] = (T)DecodeItem(_buffer, GetItemFromPool());
                _decodeIndex++;
            }
            if (_decodeCount < 1)
            {
                BuildIndex();
                _buffer.SetPosition(_decodeEndPos);
                _decodeCount = -1;
                if (!LazyDecode())
                {
                    _buffer = null;
                }
            }
            return _decodeCount;
        }
        protected virtual IDataTable DecodeItem(ByteArray buffer, T ins)
        {
            if (ins != null)
            {
                ins.Decode(buffer);
                return ins;
            }
            var data = CreateItem();
            data.Decode(buffer);
            return data;
        }
        public void SetDecodeCountPreFrame(int count)
        {
            _decodeCountPreFrame = count;
        }
        private T GetItemFromPool()
        {
            if (_itemPool.Count > 0)
            {
                return _itemPool.Dequeue();
            }
            return null;
        }


    }
}